//
// Create by Zeng Yun on 2018/12/24
// 家庭自动化部分
//

package model

import (
	"adai.design/jarvis/common/log"
	"encoding/json"
	"fmt"
	"time"
)

const (
	// 位置触发执行动作，例如: 家里有人离家，家里有人回家
	AutoTypeLocation = "location"

	// 时间触发的自动化，如工作日早上8:00 周末早上6:30
	AutoTypeTimer = "timer"

	// 属性触发的自动化，如大门打开 卧室温度大于38摄氏度
	AutoTypeCharacteristic = "characteristic"

	// 自动化执行的条件，时间段条件
	// 例如: 当客厅大门打开时，仅当下午6点至第二天凌晨6点时，才执行回家场景
	ConditionTypeTimePeriod = "time"

	// 场景执行属性条件
	// 例如，当我回家是，检测到空调温度大于30摄氏度，打开空调
	ConditionTypeCharacteristic = "characteristic"

	// 自动化执行位置条件
	// 例如: 工作日早上 8:30，仅当我在家时，才执行早上好场景
	ConditionTypeLocation = "location"
)

const (
	// 自动化类型，默认类型
	TriggerTypeCustom = ""

	// 服务属性绑定的自动化类型
	// 例如，一个情景开关绑定执行的动作和场景
	TriggerTypeServiceBind = "bind"
)

type Automation struct {
	Id   string `json:"id" bson:"id"`
	Type string `json:"type,omitempty" bson:"type,omitempty"`

	// 标题与副标题 当用户创建自动化时生成
	// 例如: title 工作日早上八点  subtitle: 执行回家早上好场景
	Title    string `json:"title" bson:"title"`
	SubTitle string `json:"subtitle" bson:"subtitle"`

	IsEnable bool `json:"enable" bson:"enable"`

	// 自动化触发条件，例如: 工作日早上8:00
	Events []*AutoEvent `json:"events" bson:"events"`
	// 自动化执行的条件，例如: 当我在家时，早上八点才能执行早上场景
	Conditions []*autoCondition `json:"conditions,omitempty" bson:"conditions,omitempty"`

	// 自动化触发之后需要执行的场景和动作
	Scenes  []string  `json:"scenes,omitempty" bson:"scenes,omitempty"`
	Actions []*Action `json:"actions,omitempty" bson:"actions,omitempty"`
}

func (a *Automation) Load() error {
	// 加载自动化触发条件
	for _, event := range a.Events {
		switch event.Type {
		case AutoTypeTimer:
			var trigger EventTimer
			err := json.Unmarshal(event.Desc, &trigger)
			if err == nil {
				event.Data = &trigger
			}

		case AutoTypeLocation:
			var trigger EventLocation
			err := json.Unmarshal(event.Desc, &trigger)
			if err == nil {
				event.Data = &trigger
			}

		case AutoTypeCharacteristic:
			var trigger EventCharacteristic
			err := json.Unmarshal(event.Desc, &trigger)
			if err == nil {
				event.Data = trigger
			}
		}
	}

	// 加载自动化执行条件
	for _, c := range a.Conditions {
		switch c.Type {
		case ConditionTypeTimePeriod:
			var condition ConditionPeriod
			err := json.Unmarshal(c.Desc, &condition)
			if err == nil {
				c.Data = &condition
			}

		case ConditionTypeLocation:
			var condition ConditionLocation
			err := json.Unmarshal(c.Desc, &condition)
			if err == nil {
				c.Data = &condition
			}

		case ConditionTypeCharacteristic:
			var condition ConditionCharacteristic
			err := json.Unmarshal(c.Desc, &condition)
			if err == nil {
				c.Data = &condition
			}
		}
	}
	return nil
}

type AutoEvent struct {
	Type string `json:"type" bson:"type"`
	// 自动化条件描述信息 json或bson格式描述数据
	Desc json.RawMessage `json:"desc" bson:"desc"`
	Data interface{}     `json:"-" bson:"-"`
}

type EventTimer struct {
	MinuteOfDay int   `json:"timer" bson:"timer"`
	Week        uint8 `json:"week" bson:"week"`
}

func (t *EventTimer) Check(now time.Time) bool {
	minuteOfDay := now.Minute() + now.Hour()*60
	if minuteOfDay != t.MinuteOfDay {
		return false
	}
	if t.Week&(0x01<<uint8(now.Weekday())) == 0x00 {
		return false
	}
	return true
}

// 定时器触发自动化推送标题信息
// 例如: 早上7:10 下午8:10
func (t *EventTimer) Title() string {
	title := ""
	if t.MinuteOfDay/60 < 12 {
		title += "上午"
	} else {
		title += "下午"
	}
	return fmt.Sprintf("%s %d:%02d", title, t.MinuteOfDay/60, t.MinuteOfDay%60)
}

const (
	ThresholdTypeEqual   = "equal"
	ThresholdTypeGreater = "greater"
	ThresholdTypeSmaller = "smaller"
)

type EventCharacteristic struct {
	Aid           string      `json:"aid" bson:"aid"`
	Sid           int         `json:"sid" bson:"sid"`
	Cid           int         `json:"cid" bson:"cid"`
	Value         interface{} `json:"value" bson:"value"`
	ThresholdType string      `json:"threshold_t" bson:"threshold_t"`
	last          time.Time   // 最后一次触发的时间
}

func (c *EventCharacteristic) check(data *Characteristic, format string) bool {
	if c.Aid != data.AId || c.Sid != data.SId || c.Cid != data.CId {
		return false
	}

	var result = false
	switch format {
	case FormatBool, FormatUInt8, FormatUInt16, FormatUInt32, FormatInt32:
		current, err := ToIntValue(data.Value)
		if err != nil {
			log.Error("event characteristic check error: %s", err)
			return false
		}
		target, err := ToIntValue(c.Value)
		if err != nil {
			log.Error("event characteristic check error: %s", err)
			return false
		}

		switch c.ThresholdType {
		case ThresholdTypeEqual:
			if current == target {
				result = true
			}
		case ThresholdTypeGreater:
			if current > target {
				result = true
			}
		case ThresholdTypeSmaller:
			if current < target {
				result = true
			}
		}
		return result

	case FormatFloat:
		current, err := ToFloatValue(data.Value)
		if err != nil {
			log.Error("event characteristic check error: %s", err)
			return false
		}
		target, err := ToFloatValue(c.Value)
		if err != nil {
			log.Error("event characteristic check error: %s", err)
			return false
		}
		switch c.ThresholdType {
		case ThresholdTypeEqual:
			if current == target {
				result = true
			}
		case ThresholdTypeGreater:
			if current > target {
				result = true
			}
		case ThresholdTypeSmaller:
			if current < target {
				result = true
			}
		}
		return result
	}
	return false
}

// 位置自动化触发条件
// 有人离开 有人达到 第一个人达到 最后一个人离开
const (
	LocationEventLeave       = "leave"
	LocationEventArrive      = "arrive"
	LocationEventFirstArrive = "first-arrive"
	LocationEventLastLeave   = "last-leave"
)

type EventLocation struct {
	Members     []string `json:"members" bson:"members"`
	TriggerType string   `json:"trigger_t" bson:"trigger_t"`
}

// 位置自动化推送内容
// 例如:
// 	云 达到了 云の家
// 	云 离开了 云の家
//  云 第一个达到了 云の家
// 	云 最后一个离开了 云の家
func (l *EventLocation) Title(member, home string) string {
	switch l.TriggerType {
	case LocationEventLastLeave:
		return member + " 最后一个离开了 " + home
	case LocationEventFirstArrive:
		return member + " 第一个达到了 " + home
	case LocationEventLeave:
		return member + " 离开了 " + home
	case LocationEventArrive:
		return member + " 到达了 " + home
	}
	return ""
}

func (l *EventLocation) Check(m *Member, ms []*Member) bool {
	// 检查是否位置变化的成员是否在触发条件的成员列表里面
	in := false
	for _, id := range l.Members {
		if id == m.Id {
			in = true
			break
		}
	}
	if in == false {
		return false
	}

	// 条件判断
	switch l.TriggerType {
	case LocationEventArrive:
		if m.State == MemberStateArrive {
			return true
		}
	case LocationEventLeave:
		if m.State == MemberStateLeave {
			return true
		}

	// 第一个人到达
	case LocationEventFirstArrive:
		if m.State != MemberStateArrive {
			return false
		}
		for _, id := range l.Members {
			if id != m.Id {
				for _, member := range ms {
					if member.Id == id && member.State == MemberStateArrive {
						return false
					}
				}
			}
		}
		return true

	// 最后一个人离开
	case LocationEventLastLeave:
		if m.State != MemberStateLeave {
			return false
		}
		for _, id := range l.Members {
			if id != m.Id {
				for _, member := range ms {
					if member.Id == id && member.State == MemberStateArrive {
						return false
					}
				}
			}
		}
		return true
	}
	return false
}

// 自动化执行条件
type autoCondition struct {
	Type string          `json:"type" bson:"type"`
	Desc json.RawMessage `json:"desc" bson:"desc"`
	Data interface{}
}

// 自动化执行条件，时间段条件, 例如早上8点至中午12点有效
type ConditionPeriod struct {
	After  int `json:"after" bson:"after"`
	Before int `json:"before" bson:"before"`
}

func (c *ConditionPeriod) Check(now time.Time) bool {
	minuteOfDay := now.Minute() + now.Hour()*60
	// 不夸天时间段
	if c.Before < c.After {
		if minuteOfDay > c.Before && minuteOfDay <= c.After {
			return true
		}
		return false
	} else {
		// 跨天时间段
		// 早上时间段或夜间时间段
		if minuteOfDay < c.Before || minuteOfDay > c.After {
			return true
		}
		return false
	}
	return false
}

// 自动化执行位置条件
const (
	// 所有人都不在家
	conditionLocationAllLeave = 0
	// 所有人都在家
	conditionLocationAllArrive = 1
	// 有人在家
	conditionLocationSomeoneArrive = 2
)

type ConditionLocation struct {
	Members       []string `json:"members" bson:"members"`
	ConditionType int      `json:"validity_t" bson:"validity_t"`
}

func (c *ConditionLocation) Check(members []*Member) bool {
	switch c.ConditionType {
	// 所有人都不在家
	case conditionLocationAllLeave:
		for _, m := range c.Members {
			for _, member := range members {
				if m == member.Id && member.State != MemberStateLeave {
					return false
				}
			}
		}
		return true

	// 所有人都在家
	case conditionLocationAllArrive:
		for _, m := range c.Members {
			for _, member := range members {
				if m == member.Id && member.State != MemberStateArrive {
					return false
				}
			}
		}
		return true

	// 有人在家
	case conditionLocationSomeoneArrive:
		for _, m := range c.Members {
			for _, member := range members {
				if m == member.Id && member.State == MemberStateArrive {
					return true
				}
			}
		}
		return false
	}
	return false
}

// 自动化执行属性条件
type ConditionCharacteristic struct {
	AId           string      `json:"aid" bson:"aid"`
	SId           string      `json:"sid" bson:"sid"`
	CId           string      `json:"cid" bson:"cid"`
	Value         interface{} `json:"value" bson:"value"`
	ThresholdType int         `json:"threshold_t" bson:"threshold_t"`
}

func (c *ConditionCharacteristic) Check(char *HMCharacteristic) bool {
	return true
}
